#include "stm32f10x.h"                  // Device header
#include "Delay.h"

//这里是单片机从软件控制SCL时钟和SDA给MPU6050发送数据，然后软件从GPIO—11口读取MPU6050的数据

void MyI2C_W_SCL(uint8_t Bitvalue)
{
	GPIO_WriteBit(GPIOB,GPIO_Pin_10,(BitAction)Bitvalue);//BitAction宏定义的作用是将一个非零值转换为逻辑高电平(1)，将零值转换为逻辑低电平(0)
	Delay_us(10);
	//写入SCL的数据，SCL对应的是GPIO10，然后需要一个BitAction类型的数据，表示1/0
}

 void MyI2C_W_SDA(uint8_t Bitvalue)
 {
	 GPIO_WriteBit(GPIOB,GPIO_Pin_11,(BitAction)Bitvalue);
	 Delay_us(10);
	 //和SCL一样，也是写入一个数据，0/1，不同的只是在11口
 }
 
 uint8_t MyI2C_R_SDA(void)
 {
	 uint8_t Bitvalue;
	 Bitvalue = GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11);
	 Delay_us(10);
	 return Bitvalue;
	 //读取SDA里面的数据
 }

void MyI2C_Init(void)
{
	/*开启时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);	//开启GPIOB的时钟
	
	/*GPIO初始化*/
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);					//将PB10和PB11引脚初始化为开漏输出
	
	/*设置默认电平*/
	GPIO_SetBits(GPIOB, GPIO_Pin_10 | GPIO_Pin_11);			//设置PB10和PB11引脚初始化后默认为高电平（释放总线状态）
}

void MyI2C_Start(void)
{
	MyI2C_W_SDA(1);												//释放SDA，确保SDA为高电平
	MyI2C_W_SCL(1);												//释放SCL，确保SCL为高电平
	MyI2C_W_SDA(0);												//在SCL高电平期间，拉低SDA，产生起始信号
	MyI2C_W_SCL(0);												//起始后把SCL也拉低，即为了占用总线，也为了方便总线时序的拼接
	//开始的时候，在SCL高电平期间，拉低SDA，然后在拉低SCL，就是开始
}

void MyI2C_Stop(void)
{
	MyI2C_W_SDA(0);							//拉低SDA，确保SDA为低电平
	MyI2C_W_SCL(1);							//释放SCL，使SCL呈现高电平
	MyI2C_W_SDA(1);							//在SCL高电平期间，释放SDA，产生终止信号
}

void MyI2C_SendByte(uint8_t Byte)			//主机给从机发送一位
{
	uint8_t i;
	for(i=0;i<8;i++)						//循环8次，发送一字节
	{
		MyI2C_W_SDA(Byte & (0x80 >> i));	//每次发送一位，使用掩码的方式取出Byte的指定一位数据并写入到SDA线
		MyI2C_W_SCL(1);						//SCL拉高，MPU6050就会在高电平期间读取这个数据
		MyI2C_W_SCL(0);						//SCL拉低，主机开始发送下一位数据
	}
	
}

uint8_t MyI2C_ReceiveByte(void)				//这个是主机读取一位，因为从机MPU6050可以自己读取
{
	uint8_t i,Byte = 0x00;
	MyI2C_W_SDA(1);							//SDA置1，表示主机释放SDA，然后从机会自己掌控SDA，然后放数据
	for(i=0;i<8;i++)
	{
		MyI2C_W_SCL(1);						//这个就是表示从机已经放好了数据了，主机表示我要读取数据了
		if(MyI2C_R_SDA() == 1)				//读取SDA的数据，看是1/0
		{
			Byte = Byte | (0x80 >> i);		//是1，就|上一个1
		}
		MyI2C_W_SCL(0);						//读完一个数据，SCL还需要拉低，让从机在放一个数据上去，
	}
	return Byte;
}

void MyI2C_SendAck(uint8_t AckBit)
{
	MyI2C_W_SDA(AckBit);					//主机把应答位数据放到SDA线
	MyI2C_W_SCL(1);							//释放SCL，从机在SCL高电平期间，读取应答位
	MyI2C_W_SCL(0);							//拉低SCL，开始下一个时序模块
}

uint8_t MyI2C_ReceiveAck(void)
{
	uint8_t AckBit;
	MyI2C_W_SDA(1);							//接收前，主机先确保释放SDA，避免干扰从机的数据发送
	MyI2C_W_SCL(1);							//释放SCL，主机机在SCL高电平期间读取SDA
	AckBit = MyI2C_R_SDA();					//将应答位存储到变量里
	MyI2C_W_SCL(0);							//拉低SCL，开始下一个时序模块
	return AckBit;							//返回定义应答位变量
}
